﻿#pragma once
#include "PhysXObj.h"
#include "NxVehicleMotor.h"
#include "NxVehicleGears.h"
#include "NxVehicleDesc.h"
#include "SoundTools.h"

_NAMESPACE_BEGIN

#define TRAIL_FREQUENCY 0.025f
#define NUM_TRAIL_POINTS 1600

/// 物理赛车类，控制赛车在场景中的物理交互和模拟

class PhysCar : public PhysXObj
{
public:
	PhysCar(CONST_REF(string)name);
	virtual ~PhysCar();
	
public:
	/// 创建赛车
	/// \param[in] lwheelMesh 左轮胎模型资源
	/// \param[in] rwheelMesh 右轮胎模型资源
	/// \param[in] carMesh 车体模型资源
	/// \param[in] vdesc 赛车的物理描述结构，用于描述所有物理参数，以实现定制不同性能的赛车
	void Create(CONST_REF(string)lwheelMesh,CONST_REF(string)rwheelMesh,CONST_REF(string)carMesh,CONST_REF(NxVehicleDesc)vdesc);

	/// 设置赛车的模型
	/// \param[in] lwheelMesh 左轮胎模型资源
	/// \param[in] rwheelMesh 右轮胎模型资源
	/// \param[in] carMesh 车体模型资源
	void SetMesh(CONST_REF(string)lwheelMesh,CONST_REF(string)rwheelMesh,CONST_REF(string)carMesh);

	/// 更新，由物理管理器调用
	void Update();

	/// 设置赛车是否可以由键盘控制
	void SetCtrled(bool val){isCtrled = val;}

	/// 返回当前是否在接受键盘控制
	bool GetCtrled(){return isCtrled;}

	/// 获取车轮的场景节点
	SceneNode* GetWheelNode(int id){return wheelNode[id];}

	/// 获取车体的场景节点
	SceneNode* GetCarNode(){return carNode;}

	/// 放缩车轮模型的大小，x y z分量
	void ScaleWheel(float x, float y, float z);

	/// 放缩车轮模型的大小，整体成比例
	void ScaleWheel(float val);

	/// 放缩车体模型的大小，x y z分量
	void ScaleCar(float x, float y, float z);

	/// 放缩车体模型的大小，整体成比例
	void ScaleCar(float val);
	
	/// 旋转车体模型
	/// \param[in] axis 需要旋转的坐标轴
	/// \param[in] angle 在该坐标轴上需要选转的角度（弧度制）
	void RotateCar(const Vector3& axis, const Radian& angle);

	/// 设置是否绑定摄像机
	void UseCamera(bool v);

	/// 获得当前速度值
	NxReal GetDriveVelocity() { return NxMath::abs(_localVelocity.x); }

	/// 获得最大速度值
	NxReal GetMaxVelocity() { return _maxVelocity; }

	/// 恢复赛车的物理未知，当车卡壳的时候手动调用
	/// 以后将修改为自动调用
	void ResetCar();


	/// 设置模型偏移值
	void SetMeshOffset(CONST_REF(Vector3) body,CONST_REF(Vector3) w0,CONST_REF(Vector3) w1,
		CONST_REF(Vector3) w2,CONST_REF(Vector3) w3);
	
protected:
	/// 更新赛车物理状态
	void UpdateVehicle(NxReal lastTimeStepSize);

	/// 控制转向
	void ControlSteering(NxReal steering, bool analogSteering);				

	/// 控制制动
	void ControlAcceleration(NxReal acceleration, bool analogAcceleration);	

	/// 计算车速
	void ComputeLocalVelocity();											

	/// 计算碰撞最多的actor
	void ComputeMostTouchedActor();											

	/// 计算角度力矩
	NxReal ComputeAxisTorque();

	/// 
	NxReal ComputeRpmFromWheels();

	/// 
	NxReal ComputeMotorRpm(NxReal rpm);

	/// 
	NxReal GetGearRatio();

	/// 提高一个档位
	void GearUp();

	/// 降低一个档位
	void GearDown();

	/// 更新RPM
	void UpdateRpms();

	/// 更新中调用的控制函数，控制刹车力矩，动力矩，转向等
	void Control (NxReal steering, bool analogSteering, NxReal acceleration, bool analogAcceleration, bool handBrake);

	/// 绑定的摄像机更新函数
	void CameraUpdate();

	/// 仪表盘更新
	void DataPanelUpdate();		

	/// 创建推进器粒子系统
	void CreateThruster();		

	/// N2O推进器更新
	void NitroThrusterUpdate();	

	/// 设置N20推进器
	void SetNitroThruster();	

	/// N2O槽状态更新
	void NitroPanelUpdate();	

	/// 漂移处理
	void ProcessExcursion();	

	/// 调试视角
	void DebugViewUpdate();


public:
	
	/// 视角模式
	enum ViewMode
	{
		/// 第一人称
		FirstPerson,		
		
		/// 控制台视角
		Console,			
		
		/// 第三人称
		ThirdPerson			

	};	

	/// 设置视角模式
	void SetViewMode(PhysCar::ViewMode mode){m_ViewMode = mode;}

	/// 获取当前的视角模式
	PhysCar::ViewMode GetViewMode(){return m_ViewMode;}

protected:
	string	carName;

	/// 车是否被控制
	bool isCtrled;	

	/// 是否在控制摄像机
	bool useCamera;	

	/// 车是否为飘移状态
	bool excursion;				

	/// 当前启用的视角模式
	ViewMode	m_ViewMode;

	/// 仪表盘
	Overlay* panel;				

	/// N2O面板
	Overlay* nitroPanel;		

	/// 仪表盘指针纹理
	TextureUnitState* cursorTex;

	/// 四个车轮
	NxWheelShape* wheel[4];		

	/// 车轮节点
	SceneNode* wheelNode[4];	

	/// 车轮实体
	Entity*	   wheelEntity[4];	

	/// 车体节点
	SceneNode* carNode;			

	/// 车体实体
	Entity*	   carEntity;		

	/// 摄象机自身结点
	SceneNode *mCameraNode;		

	/// 摄像机距离
	Vector3 m_cameradistVec;	

	/// 偏移量
	Vector3 m_cameralookoffset;	


	NxActor*				_mostTouchedActor;

	std::vector<WheelShape*>		_wheels;

	NxReal					_maxVelocity;
	NxReal					_steeringWheelState;
	NxReal					_digitalSteeringDelta;
	bool					_releaseBraking;
	bool					_braking;
	NxReal					_accelerationPedal;
	NxReal					_brakePedal;
	bool					_brakePedalChanged;
	bool					_handBrake;
	NxVec3					_localVelocity;
	NxReal					_lastTrailTime;
	NxU32					_nextTrailSlot;
	NxVec3					_steeringTurnPoint;
	NxVec3					_steeringSteerPoint;

	NxVehicleMotor*			_vehicleMotor;
	NxReal					_motorForce;
	NxVehicleGears*			_vehicleGears;
	NxReal					_differentialRatio;
	NxReal					_transmissionEfficiency;
	NxReal					_steeringMaxAngleRad;

	/// 记录轮胎印的缓冲区
	NxVec3					_trailBuffer[NUM_TRAIL_POINTS];	

	void*					userData;
	NxMaterial*				_carMaterial;

protected:
	
	/// 发动机声音
	SoundEffect*			engineSound;	

	/// 刹车声音
	SoundEffect*			breakSound;		

	/// 推进器声音
	SoundEffect*			thrusterSound;	

protected:

	/// 粒子系统(N2O推进器使用后的喷火效果)
	ParticleSystem*			pThrusters;



	SceneNode*				thrustersNode;	

	/// 推进器粒子 左
	ParticleEmitter*		thrusterLeft;	

	/// 推进器粒子 右
	ParticleEmitter*		thrusterRight;	

	/// 当前是否在使用N2O推进器
	bool					isThruster;		

	/// 推进器速度系数
	float					thrusterParm;	

	/// 推进器计时器
	Clock					thrusterClock;	

	/// 三个n2o槽状态
	float					nitroPercent[3];

	/// 车体模型的偏移
	Vector3					bodyMeshOffset;

	/// 车轮的偏移
	Vector3					wheelMeshOffset[4];

	/// 轮胎痕的属性
	NameValuePairList		pairList;

	/// 轮胎痕
	RibbonTrail*			pSkidMark[2];

	/// 轮胎后的灰尘 
	ParticleSystem*			pSkidDust[2];
};

_NAMESPACE_END